﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Drawing;
using System.Threading;

using GMap.NET.CacheProviders;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using GMap.NET;

using FLEN_Sim.funct;
using FLEN_Sim.gui.map;
using FLEN_Sim.containerobjects;
using FLEN_Sim.config;

namespace FLEN_Sim
{
    public partial class FLEN_Sim_GUI : Form
    {
        private List<Hospital> hospitals = new List<Hospital>();
        private List<AmbulanceStation> ambstations = new List<AmbulanceStation>();
        private List<AmbulanceVehicle> vehicles = new List<AmbulanceVehicle>();
        private List<Emergency> emergencies = new List<Emergency>();
        private GMapOverlay overlay_hospitals, overlay_ambulancestations, overlay_vehicles, overlay_routes, overlay_emergencies;
        private Quazistax.Win.QQDragImageForm dragImageForm = new Quazistax.Win.QQDragImageForm();
        private object dragSource = null;
        private Point sourcePoint;
        private List<Thread> threadList = new List<Thread>();

        public FLEN_Sim_GUI()
        {
            this.startup();

            InitializeComponent();

            Config.CONTROL = this.gMapControl;
            Config.THREAD_LIST = this.threadList;
            Config.textbox = textBox1;
            

            //Initialize gMapControl
            //Map access only through server, so internet is required!
            //Using OpenStreetMap
            GMaps.Instance.Mode = AccessMode.ServerOnly;
            gMapControl.MapType = GMap.NET.MapType.OpenStreetMap;
            gMapControl.MinZoom = 1;
            gMapControl.MaxZoom = 17;
            gMapControl.Zoom = 11;
            gMapControl.RoutesEnabled = true;
            gMapControl.MarkersEnabled = true;

            //Pointing to Witten (or somewhere nearby ;) )
            gMapControl.Position = new PointLatLng(51.3861, 7.2510);

            {
                //MapOverlay for Hospitals
                overlay_hospitals = new GMapOverlay(gMapControl, "Krankenhäuser");
                gMapControl.Overlays.Add(overlay_hospitals);

                //MapOverlay for ambulance stations
                overlay_ambulancestations = new GMapOverlay(gMapControl, "Rettungswachen");
                gMapControl.Overlays.Add(overlay_ambulancestations);

                //MapOverlay for vehicles
                overlay_vehicles = new GMapOverlay(gMapControl, "Fahrzeuge");
                gMapControl.Overlays.Add(overlay_vehicles);

                //MapOverlay for routes
                overlay_routes = new GMapOverlay(gMapControl, "Routen");
                gMapControl.Overlays.Add(overlay_routes);

                //MapOverlay for emergencies
                overlay_emergencies = new GMapOverlay(gMapControl, "Notfälle");
                gMapControl.Overlays.Add(overlay_emergencies);

            }

            {
                DataHandler.createObjectsFromXML(out hospitals, out ambstations, out vehicles, ref gMapControl);

                foreach (Hospital hosp in hospitals)
                {
                    overlay_hospitals.Markers.Add(hosp.Marker);
                }
                foreach (AmbulanceStation station in ambstations)
                {
                    overlay_ambulancestations.Markers.Add(station.Marker);
                }
            }

            Emergency bla = EmergencyGenerator.createRandom();
            overlay_emergencies.Markers.Add(bla.Marker);
            emergencies.Add(bla);

            this.Activate();

            //Load it
            gMapControl.Refresh();

            textBox1.AppendText("KHs:\n");

            foreach (Hospital h in hospitals)
            {
                textBox1.AppendText(h.ID + "\n");
            }

            textBox1.AppendText("Wachen:\n");

            foreach (AmbulanceStation s in ambstations)
            {
                textBox1.AppendText("- " + s.ShortID + " hat Fzge:\n");

                foreach (AmbulanceVehicle v in s.Vehicles)
                {
                    textBox1.AppendText("-- " + v.Callsign + " - Status: "+v.Status+"\n");
                }
            }

            foreach (AmbulanceVehicle v in vehicles)
            {
                listView_Vehicles.Items.Add(new ListViewItem(new string[] {v.Callsign.ToString(),v.Status.ToString(), DataHandler.getVehicleTypeFromTypeNumber(v.Type)}));
                listView_Vehicles.Items[listView_Vehicles.Items.Count - 1].BackColor = Config.STATUS_2;
                listView_Vehicles.Items[listView_Vehicles.Items.Count - 1].ForeColor = System.Drawing.Color.White;

                
            }

            treeView_emergencies.Nodes.Add(new TreeNode(bla.Address, new TreeNode[] {new TreeNode("Uhrzeit"), new TreeNode("Fzg"), new TreeNode("Gespräch")}));
        }

        #region Event-Methoden

        #region Drag&Drop für Fahrzeuge aus Liste in Einsätze rein

        /// <summary>
        /// Triggert, wenn im ListView eine Maustaste gedrückt wird.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listView_Vehicles_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button.Equals(MouseButtons.Left))
            {
                dragSource = this;
                sourcePoint = e.Location;
            }
        }

        /// <summary>
        /// Triggert, wenn die Maus mit einem Drag in den Bereich des TreeViews Einsätze gezogen wird.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void treeView_emergencies_DragEnter(object sender, DragEventArgs e)
        {
            foreach (string xsFormat in e.Data.GetFormats())
            {
                if (xsFormat.Equals(typeof(List<AmbulanceVehicle>).ToString()))
                {
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        /// <summary>
        /// Triggert, wenn man die Maus mit einem Drag über der Treeview loslässt.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void treeView_emergencies_DragDrop(object sender, DragEventArgs e)
        {
            List<AmbulanceVehicle> ambs = (List<AmbulanceVehicle>)e.Data.GetData(typeof(List<AmbulanceVehicle>).ToString());
            TreeNode dragNode = treeView_emergencies.GetNodeAt(treeView_emergencies.PointToClient(new System.Drawing.Point(e.X, e.Y)));
            bool cont = true;

            if (dragNode != null)
            {

                Emergency dragged = null;
                TreeNode addressNode = null;

                switch (dragNode.Level)
                {
                    case 0:
                        foreach (AmbulanceVehicle v in ambs)
                        {
                            if (!dragNode.Nodes[1].Nodes.ContainsKey(v.Callsign))
                            {
                                dragNode.Nodes[1].Nodes.Add(v.Callsign, v.Callsign);
                                addressNode = dragNode;
                            }
                            else
                            {
                                cont = false;
                            }
                        }
                        break;
                    case 1:
                        foreach (AmbulanceVehicle v in ambs)
                        {
                            if (!dragNode.Parent.Nodes[1].Nodes.ContainsKey(v.Callsign))
                            {
                                dragNode.Parent.Nodes[1].Nodes.Add(v.Callsign, v.Callsign);
                                addressNode = dragNode.Parent;
                            }
                            else
                            {
                                cont = false;
                            }
                        }
                        break;
                    case 2:
                        foreach (AmbulanceVehicle v in ambs)
                        {
                            if (!dragNode.Parent.Parent.Nodes[1].Nodes.ContainsKey(v.Callsign))
                            {
                                dragNode.Parent.Parent.Nodes[1].Nodes.Add(v.Callsign, v.Callsign);
                                addressNode = dragNode.Parent.Parent;
                            }
                            else
                            {
                                cont = false;
                            }
                        }
                        break;
                    default:
                        cont = false;
                        break;
                }
                

                if (cont)
                {
                    foreach (Emergency em in emergencies)
                    {
                        if (em.Address.Equals(addressNode.Text))
                        {
                            dragged = em;
                            break;
                        }
                    }

                    foreach (AmbulanceVehicle v in ambs)
                    {
                        v.assignToEmergency(dragged);
                    }
                }
            }
        }

        private void listView_Vehicles_MouseMove(object sender, MouseEventArgs e)
        {
            if (dragSource != null && (Math.Abs(sourcePoint.X - e.X) > SystemInformation.DragSize.Width / 2 || Math.Abs(sourcePoint.Y - e.Y) > SystemInformation.DragSize.Height / 2))
            {
                ListViewItem lvDragSource = listView_Vehicles.SelectedItems[0];

                Bitmap bmp;
                int margin = 4;
                using (Graphics forMeasure = this.CreateGraphics())
                {
                    SizeF textSize = forMeasure.MeasureString(lvDragSource.Text, lvDragSource.Font, lvDragSource.Bounds.Width);
                    bmp = new Bitmap((int)textSize.Width + margin * 2, (int)textSize.Height + margin * 2, forMeasure);
                }
                using (Graphics draw = Graphics.FromImage(bmp))
                {
                    draw.Clear(lvDragSource.BackColor);
                    using (Brush brush = new SolidBrush(lvDragSource.ForeColor))
                        draw.DrawString(lvDragSource.Text, lvDragSource.Font, brush, new RectangleF(margin, margin, bmp.Width - margin * 2 + 1, bmp.Height - margin * 2 + 1));
                }
                dragImageForm.Show(bmp, 20, 20);

                try
                {

                    string callsign;
                    List<AmbulanceVehicle> selectedAmbs = new List<AmbulanceVehicle>();

                    foreach (ListViewItem item in listView_Vehicles.SelectedItems)
                    {
                        callsign = item.SubItems[0].Text;

                        foreach (AmbulanceVehicle v in vehicles)
                        {
                            if (v.Callsign.Equals(callsign))
                            {
                                selectedAmbs.Add(v);
                                break;
                            }
                        }

                    }

                    IDataObject dataObj = new DataObject(typeof(List<AmbulanceVehicle>).ToString(), selectedAmbs);

                    listView_Vehicles.DoDragDrop(dataObj, DragDropEffects.All);
                }
                finally
                {
                    dragSource = null;
                    dragImageForm.Hide();
                }
            }
        }

        private void listView_Vehicles_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button.Equals(MouseButtons.Left))
            {
                dragSource = null;
            }
        }

        private void listView_Vehicles_MouseLeave(object sender, EventArgs e)
        {
            dragSource = null;
        }

        private void listView_Vehicles_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            dragImageForm.SyncLocationWithMouse();
        }
        #endregion

        //Zeigt oder versteckt Krankenhausmarker auf der Map
        private void checkBox_showHospitals_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox_showHospitals.Checked)
            {
                foreach (Hospital hospital in this.hospitals)
                {
                    this.overlay_hospitals.Markers.Add(hospital.Marker);
                }

                gMapControl.Refresh();
            }
            else
            {
                this.overlay_hospitals.Markers.Clear();
                gMapControl.Refresh();
            }
        }

        //Zeigt oder versteckt Rettungswachen auf der Map
        private void checkBox_showAmbStations_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox_showAmbStations.Checked)
            {
                foreach (AmbulanceStation station in this.ambstations)
                {
                    this.overlay_ambulancestations.Markers.Add(station.Marker);
                }

                gMapControl.Refresh();
            }
            else
            {
                this.overlay_ambulancestations.Markers.Clear();
                gMapControl.Refresh();
            }
        }

        #endregion

        #region Private Hilfsmethoden

        private void startup()
        {
            //Überprüft, ob alle benötigten Dateien in \data\ vorh. sind
            if (Directory.Exists("data"))
            {
                if (!File.Exists("data\\Hospitals.xml"))
                {
                    MessageBox.Show("Datei 'data\\Hospitals.xml' nicht gefunden!\nBeende Programm.", "Schwerer Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                if (!File.Exists("data\\AmbulanceStations.xml"))
                {
                    MessageBox.Show("Datei 'data\\AmbulanceStations.xml' nicht gefunden!\nBeende Programm.", "Schwerer Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                if (!File.Exists("data\\Vehicles.xml"))
                {
                    MessageBox.Show("Datei 'data\\Vehicles.xml' nicht gefunden!\nBeende Programm.", "Schwerer Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                MessageBox.Show("Verzeichnis 'data' nicht gefunden!\nBeende Programm.", "Schwerer Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        private void button_status2_Click(object sender, EventArgs e)
        {
            vehicles[1].Status = 2;
        }

        private void button_status3_Click(object sender, EventArgs e)
        {
            vehicles[1].Status = 3;
        }

        private void button_status6_Click(object sender, EventArgs e)
        {
            vehicles[1].Status = 6;
        }

        public GMap.NET.WindowsForms.GMapOverlay getOverlayVehicles()
        {
            return overlay_vehicles;
        }
    }
}
